package korkd.tower;


import java.util.LinkedList;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.camera.hud.HUD;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.util.FPSCounter;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.path.ITiledMap;
import org.anddev.andengine.util.path.astar.AStarPathFinder;
import org.anddev.andengine.util.path.Path;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.Toast;

public class TowerDefenseGame2 extends BaseGameActivity implements IOnSceneTouchListener {
	// ===========================================================
	// Constants
	// ===========================================================

	private static final int CAMERA_WIDTH = 320;
	private static final int CAMERA_HEIGHT = 480;
	

	// ===========================================================
	// Fields
	// ===========================================================

	//private BoundCamera mBoundChaseCamera;

	protected Scene mMainScene;
	
	private BitmapTextureAtlas mTexture;
	private BoundCamera mBoundCamera;
	private float mTouchX = 0, mTouchY = 0, mTouchOffsetX = 0, mTouchOffsetY = 0;
	private BitmapTextureAtlas mFontTexture;
	private Font mFont;
	private ChangeableText mFPSText;
	private Map mTowerMap;
	private TiledTextureRegion mPlayerTextureRegion;
	private TextureRegion mTowerTextureRegion;
	private Context mContext;
	private LinkedList<Tower> mTowers = new LinkedList<Tower>();
	private boolean mPlaceTower = false;
	private Path mPath;
	private TextureRegion mBulletTextureRegion;
	private TowerDefenseGame2 TDGame = this;
	private Intent resultIntent;
	private int mUnitSpawned = 25;
	private TextureRegion mTowerRangeTextureRegion;
	private LinkedList<TMXTile> mUsedTiles = new LinkedList<TMXTile>();
	private UnitPool mUnitPool;
	private BulletPool mBulletPool;
	
	// ===========================================================
	// Constructors
	// ===========================================================

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	@Override
	public Engine onLoadEngine() 
	{
		this.mBoundCamera = new BoundCamera(0,0,CAMERA_WIDTH,CAMERA_HEIGHT);
		return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mBoundCamera));
	}

	@Override
	public void onLoadResources() 
	{
		this.mFontTexture = new BitmapTextureAtlas(128,128,TextureOptions.NEAREST_PREMULTIPLYALPHA);
		this.mFont = new Font(this.mFontTexture, Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD), 24, true, Color.YELLOW);
		this.mEngine.getTextureManager().loadTexture(this.mFontTexture);
		this.mEngine.getFontManager().loadFont(this.mFont);
		
		this.mTexture = new BitmapTextureAtlas(256, 256, TextureOptions.DEFAULT);
		this.mTowerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mTexture, this, "gfx/tower.png", 0, 0);
		this.mEngine.getTextureManager().loadTexture(this.mTexture);
		
		this.mTexture = new BitmapTextureAtlas(128, 128, TextureOptions.DEFAULT);
		this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture, this, "gfx/player.png", 0, 0, 3, 4); // 72x128
		this.mEngine.getTextureManager().loadTexture(this.mTexture);
		
		this.mTexture = new BitmapTextureAtlas(16, 16, TextureOptions.DEFAULT);
		this.mBulletTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/bullet.png", 0, 0);
		this.mEngine.getTextureManager().loadTexture(this.mTexture);
		
		this.mTexture = new BitmapTextureAtlas(256, 256, TextureOptions.DEFAULT);
		this.mTowerRangeTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/TowerRange.png", 0, 0);
		this.mEngine.getTextureManager().loadTexture(this.mTexture);
		
	}

	@Override
	public Scene onLoadScene() 
	{
		final FPSCounter fpsCounter = new FPSCounter();
		this.mEngine.registerUpdateHandler(fpsCounter);
		
	    mMainScene = new Scene();
		mMainScene.setOnSceneTouchListener(this);
		
		//mTowerMap = new Map("tmx/TD.tmx");
		
		generatePath(21,44,21,0);
		
		Bundle extra = getIntent().getExtras();
		int CastleHealth = extra.getInt("CastleHealth");

		mUnitPool = new UnitPool(mPlayerTextureRegion, mMainScene, mTowerMap.getMap(), mPath, CastleHealth);
		
		mBulletPool = new BulletPool(mBulletTextureRegion,mMainScene);
		
		/* Make the camera not exceed the bounds of the TMXLayer. */
		this.mBoundCamera.setBounds(0, mTowerMap.getWidth(), 0, mTowerMap.getHeight());
		this.mBoundCamera.setBoundsEnabled(true);
		
		mMainScene.attachChild(mTowerMap.getMap().getTMXLayers().get(0));

		mMainScene.setTouchAreaBindingEnabled(true);
		
		mContext = this;
		
		Sprite towerButton = new Sprite(0, 0, mTowerTextureRegion)
		{
			@Override
			public boolean onAreaTouched(final TouchEvent pTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY)
			{				
				if(pTouchEvent.getAction() == MotionEvent.ACTION_DOWN)
				{
					this.setColor(0.8f,0.8f,0.8f,0.3f);
				}
				if(pTouchEvent.getAction() == MotionEvent.ACTION_UP)
				{
					this.setColor(1.0f,1.0f,1.0f,0.6f);
					CreateTower();
				}
				return true;
			}
		};
		
		towerButton.setScale(0.6f);
		towerButton.setPosition(CAMERA_WIDTH - towerButton.getWidth(), CAMERA_HEIGHT - towerButton.getHeight());
		towerButton.setAlpha(0.6f);
		
		final ChangeableText GoldCount = new ChangeableText(0,0, this.mFont, "Gold: ", 12);
		mFPSText = new ChangeableText(100,0, this.mFont, "FPS: ", 7);
		
		final HUD hud = new HUD();
		hud.attachChild(GoldCount);
		hud.attachChild(mFPSText);
		hud.attachChild(towerButton);
		hud.registerTouchArea(towerButton);
		this.mBoundCamera.setHUD(hud);

		mMainScene.registerUpdateHandler(new IUpdateHandler() 
		{
			@Override
			public void onUpdate(float pSecondsElapsed)
			{
				if(mUnitPool.getCastleHealth() == 0)
				{
					resultIntent = new Intent();
					resultIntent.putExtra("result",true);
					setResult(Activity.RESULT_OK, resultIntent);
					TDGame.finish();
				}
				else if(mUnitPool.getCount() == 25)
				{
					resultIntent = new Intent();
					resultIntent.putExtra("result",false);
					setResult(Activity.RESULT_OK, resultIntent);
					TDGame.finish();
				}
			}

			@Override
			public void reset() {
				// TODO Auto-generated method stub
			}
		});
		
		mMainScene.registerUpdateHandler(new TimerHandler(1.0f, true, new ITimerCallback() 
		{
			@Override
			public void onTimePassed(TimerHandler pTimerHandler) 
			{
				if(mUnitSpawned != 0)
				{
					mUnitPool.obtainPoolItem();
					mUnitSpawned--;
				}
				else
				{
					mMainScene.unregisterUpdateHandler(pTimerHandler);
				}
			}
		}));
		
		return mMainScene;
	}

	@Override
	public void onLoadComplete() {

	}
	
	private void CreateTower() 
	{
		Toast.makeText(mContext, "Press screen to place a tower", Toast.LENGTH_LONG).show();
		mTowers.add(new Tower(0,0, mTowerTextureRegion, mTowerRangeTextureRegion, mUnitPool, mBulletPool));
		//mTowers.getLast().attachChild(TowerRegion);
		
		mTowers.getLast().create(mTowerMap.getMap(), mMainScene, mUsedTiles);

		mPlaceTower = true;
	}
	
	public void generatePath(int pStartCol, int pStartRow, int pEndCol, int pEndRow)
	{		
		final ITiledMap<TMXLayer> tmap = new ITiledMap<TMXLayer>()
		{
			@Override
			public int getTileColumns() {
				return mTowerMap.getMap().getTileColumns();
			}
			
			@Override
			public int getTileRows()
			{
				return mTowerMap.getMap().getTileRows();
			}
			
			@Override
			public boolean isTileBlocked(TMXLayer pTile, final int pTileColumn, final int pTileRow)
			{
				return false;
			}
			
			@Override
			public float getStepCost(final TMXLayer pTile, final int pFromTileColumn, final int pFromTileRow, final int pToTileColumn, final int pToTileRow)
			{
				TMXProperty cost = mTowerMap.getMap().getTMXLayers().get(0).getTMXTile(pToTileColumn, pToTileRow).getTMXTileProperties(mTowerMap.getMap()).get(0);
				return Float.parseFloat(cost.getValue());
				
			}
			
			@Override
			public void onTileVisitedByPathFinder(int pTileColumn, int pTileRow) {
				// Do Nothing
			}
		};
		
		AStarPathFinder<TMXLayer> AStar = new AStarPathFinder<TMXLayer>(tmap, 200, false);

		mPath = AStar.findPath(this.mTowerMap.getMap().getTMXLayers().get(0), 100000, pStartCol, pStartRow, pEndCol, pEndRow);
		
		if(mPath == null)
		{
			throw new Error("mAPath returned NULL");
		}
	}
	
	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pTouchEvent)
	{		
		if(mPlaceTower)
		{
			if(mTowers.getLast().place(pTouchEvent, mBoundCamera, mUsedTiles))
			{
				mTowers.removeLast();
			}
			
			if(pTouchEvent.getAction() == MotionEvent.ACTION_UP)
			{
				mPlaceTower = false;
			}
		}
		else
		{
			if(pTouchEvent.getAction() == MotionEvent.ACTION_DOWN)
	        {
					mTouchX = pTouchEvent.getMotionEvent().getX();
	                mTouchY = pTouchEvent.getMotionEvent().getY();
	        }
	        else if(pTouchEvent.getAction() == MotionEvent.ACTION_MOVE)
	        {
	                float newX = pTouchEvent.getMotionEvent().getX();
	                float newY = pTouchEvent.getMotionEvent().getY();
	               
	                mTouchOffsetX = (newX - mTouchX);
	                mTouchOffsetY = (newY - mTouchY);
	               
	                float newScrollX = this.mBoundCamera.getCenterX() - mTouchOffsetX;
	                float newScrollY = this.mBoundCamera.getCenterY() - mTouchOffsetY;
	               
	                this.mBoundCamera.setCenter(newScrollX, newScrollY);
	               
	                mTouchX = newX;
	                mTouchY = newY;
	                
	        }
	        else if(pTouchEvent.getAction() == MotionEvent.ACTION_UP)
	        {
	        }
		}

		
        return true;
	}
	
	@Override
	public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) 
	{
		if(pKeyCode == KeyEvent.KEYCODE_MENU && pEvent.getAction() == KeyEvent.ACTION_DOWN) {
			return true;
		} else {
			return super.onKeyDown(pKeyCode, pEvent);
		}
	}

	// ===========================================================
	// Methods
	// ===========================================================

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}